/*
 * Copyright 2008 Andrej Herich
 * 
 * http://azetclient.yw.sk/
 * http://azetclient.googlecode.com/
 * 
 * This file is part of AzetClient.
 * 
 * AzetClient is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * AzetClient is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with AzetClient.  If not, see <http://www.gnu.org/licenses/>.
 */

package sk.yw.azetclient.gui;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.swing.AbstractListModel;
import sk.yw.azetclient.managers.BuddyListManagerEvent;
import sk.yw.azetclient.managers.BuddyListManagerListener;
import sk.yw.azetclient.model.Buddy;

/**
 *
 * @author error216
 */
public class BuddyListModel extends AbstractListModel
        implements Comparator<Buddy>, BuddyListManagerListener {
    
    private static final long serialVersionUID = 544199254l;
    
    private static Buddy separator = new Buddy();
    static { getSeparator().setName("---"); }

    public static Buddy getSeparator() {
        return separator;
    }
    
    private List<Buddy> list = new ArrayList<Buddy>();
    private int separatorIndex;
    
    public BuddyListModel() {
        list.add(separator);
        separatorIndex = 0;
    }

    public int getSize() {
        return list.size();
    }

    public Object getElementAt(int index) {
        return list.get(index);
    }

    public void buddyAdded(BuddyListManagerEvent event) {
        add(event.getBuddy(), 0);
    }

    public void buddyChanged(BuddyListManagerEvent event) {
        Buddy newBuddy = event.getBuddy();
        int i = list.indexOf(newBuddy);
        
        // if buddy is in right place according to sort...
        if ((i == 0 || compare(list.get(i - 1), newBuddy) < 0)
                && (i == separatorIndex - 1
                || compare(newBuddy, list.get(i+1)) < 0)) {
            fireContentsChanged(this, i, i);
        } else {
            remove(newBuddy);
            add(newBuddy, 0);
        }
    }

    public void buddyRemoved(BuddyListManagerEvent event) {
        remove(event.getBuddy());
    }

    public void otherAdded(BuddyListManagerEvent event) {
        add(event.getBuddy(), separatorIndex + 1);
    }

    public void otherChanged(BuddyListManagerEvent event) {
        Buddy newBuddy = event.getBuddy();
        int i = list.indexOf(newBuddy);
        
        // if buddy is in right place according to sort...
        if ((i == separatorIndex + 1 || compare(list.get(i - 1), newBuddy) < 0)
                && (i == list.size() - 1
                || compare(newBuddy, list.get(i+1)) < 0)) {
            fireContentsChanged(this, i, i);
        } else {
            remove(newBuddy);
            add(newBuddy, separatorIndex + 1);
        }
    }

    public void otherRemoved(BuddyListManagerEvent event) {
        remove(event.getBuddy());
    }
    
    private void add(Buddy buddy, int offset) {
        int i = offset;
        while (compare(buddy, list.get(i)) > 0
                && i != separatorIndex
                && i < list.size()) i++;
        list.add(i,buddy);
        if (i <= separatorIndex) separatorIndex++;
        fireIntervalAdded(this, i, i);
    }
    
    private void remove(Buddy buddy) {
        int i = list.indexOf(buddy);
        list.remove(i);
        if (i < separatorIndex) separatorIndex--;
        fireIntervalRemoved(this, i, i);
    }
    
    public void initialAdd(Collection<Buddy> collection) {
        if (collection == null)
            throw new IllegalArgumentException("Null pointer in collection");
        
        if (list.size() > 1)
            throw new IllegalStateException("Buddy list not in initial state");
        
        SortedSet<Buddy> buddies = new TreeSet<Buddy>(this);
        buddies.addAll(collection);
        
        list = new ArrayList<Buddy>(buddies);
        separatorIndex = list.size();
        list.add(getSeparator());
        
        fireIntervalAdded(this, 0, list.size() - 1);
    }

    public int compare(Buddy buddy1, Buddy buddy2) {
        if (buddy1.getStatus().ordinal() < buddy2.getStatus().ordinal())
            return -1;
        
        if (buddy1.getStatus().ordinal() > buddy2.getStatus().ordinal())
            return 1;
        
        return buddy1.compareTo(buddy2);
    }
    
}
